﻿#pragma once
#include <chrono>
#include <array>
#include <string>

/**
 * https://en.cppreference.com/w/cpp/chrono/c/strftime
 * @brief The Date class
 */
class Date : public std::array<uint16_t, 6>
{
public:
    Date();
    Date(const std::chrono::system_clock::time_point& time);
    Date(const time_t& time);
    Date(const std::tm* tm);
    /**
     2020-04-03 13:34:15
     %Y year 2020
     %m moth 04
     %d day 03
     %H hour
     %M minute
     %S second
     */
    Date(const std::string& text, const char* format=nullptr);
    Date(const std::array<uint16_t, 6>& date);
    Date(const Date& date);
public:
    void set(const std::chrono::system_clock::time_point& time);
    void set(const time_t& time);
    void set(const std::tm* tm);
    void set(const std::string& text, const char* format=nullptr);
    void set(const std::array<uint16_t, 6>& date);
    void set(const Date& date);
public:
    using std::array<uint16_t, 6>::operator[];
    uint16_t& operator[](const std::string& key);
    const uint16_t& operator[](const std::string& key) const;

    inline uint16_t& year()    {return (*this)[0];}
    inline uint16_t& month()   {return (*this)[1];}
    inline uint16_t& day()     {return (*this)[2];}
    inline uint16_t& hour()    {return (*this)[3];}
    inline uint16_t& minute()  {return (*this)[4];}
    inline uint16_t& second()  {return (*this)[5];}

    inline const uint16_t& year() const    {return (*this)[0];}
    inline const uint16_t& month() const   {return (*this)[1];}
    inline const uint16_t& day() const     {return (*this)[2];}
    inline const uint16_t& hour() const    {return (*this)[3];}
    inline const uint16_t& minute() const  {return (*this)[4];}
    inline const uint16_t& second() const  {return (*this)[5];}
public:
    operator time_t() const;
    operator std::tm*() const;

    std::string to_string(const char* format=nullptr) const;
    std::tm* to_gmtime() const;
    std::tm* to_localtime() const;
public:
    //每年的第几周
    uint16_t getYearWeek() const;
    //每年的第几天
    uint16_t getYearDay() const;
    //每周的第几天
    uint16_t getWeekDay() const;
    //距离1970年1月1日第几天
    uint16_t getTimeDay() const;
    void setTimeDay(const uint16_t& day);

    bool leap() const;
public:
    template <typename T>
    static typename std::enable_if<std::is_integral<T>::value, bool>::type
    leap(const T& year) {
        return year >= 0 && (year%400==0 || (year%4==0 && year%100!=0));
    }
    /**
     * 系统时间/时间戳
     */
    template <typename T=std::chrono::milliseconds>
    static uint64_t now() {
        auto now = std::chrono::system_clock::now();
        auto cur = std::chrono::time_point_cast<T>(now);
        return cur.time_since_epoch().count();
    }
    /**
     * 用来计算时间间隔。
     */
    template <typename T=std::chrono::milliseconds>
    static uint64_t clock() {
        auto now = std::chrono::steady_clock::now();
        auto cur = std::chrono::time_point_cast<T>(now);
        return cur.time_since_epoch().count();
    }
};

